hooked on herbstluftwm

sunday, 27 september 2015

tiling window managers are often choices for “riced” computer desktop environments—the reason being, that the more popular stacking window managers such as Windows, OSX or Gnome, merely impose a standard look or appearance to applications which, for all intensive purposes, are randomly organized on the desktop.

Tiling window managers, on the other hand, effectively partition the desktop space into containers for applications. Hence, the display is organized into non-overlapping rectangular regions for maximum content viewing, often symmetrically—floating windows do permit overlap or stacking but that is not why tiling window managers are chosen.

Automatic tiling window managers continually partition the display as new application windows are opened, creating smaller and smaller windows (often with a single large master window). herbstluftwm is a manual tiling manager which populates the subframe containing focus with application windows in accordance with the subframe’s current layout rule (horizontal, vertical, grid, max).

Thus, to open a window in an adjacent subframe, focus has to be manually brought to that subframe via the mouse or a keybind action. What this allows is a great deal of control over how the desktop work space is partitioned and where application windows are displayed. This is the beauty of manual tiling window managers.

I generally prefer to open windows in available empty subframes—large displays benefit especially with the use of subframes—and, in the absence of such, in adjacent occupied subframes so the latest applications are always visible (in max layout, the new application window would stack above the previous application window).

To add this and other behaviors to herbstluftwm, effectively transforming herbstluftwm into a more dynamic tiling window manager, emit_hooks are used to extend its window handling behaviour.

focus frame

finds an empty subframe to open (spawn) a window in..

tag=$(herbstclient list_monitors | grep '\[FOCUS\]' | cut -d'"' -f2) herbstclient cycle_frame -1 for i in $(seq 1 $(herbstclient attr tags.by-name.$tag.frame_count)) do herbstclient cycle_frame 1 (( $(herbstclient attr tags.by-name.$tag.curframe_wcount) )) || break done

Add to the herbstluftwm autostart application launcher and keybind spawns..

hc keybind Super-space chain . emit_hook focus_frame . spawn dmenu_run hc keybind $Mod-Shift-Return chain . emit_hook focus_frame . spawn urxvt -title 'terminal' -name 'terminal' ..

focus window

brings focus to a non-empty subframe. This is useful when a subframe is emptied of application windows..

tag=$(herbstclient list_monitors | grep '\[FOCUS\]' | cut -d'"' -f2) frames=$(herbstclient attr tags.by-name.$tag.frame_count) herbstclient cycle_frame -1 for i in $(seq 1 $frames) do herbstclient cycle_frame 1 (( $(herbstclient attr tags.by-name.$tag.curframe_wcount) )) && break [[ $i -eq $frames ]] && herbstclient cycle_frame 1 done

An empty desktop retains focus on the original subframe.

Add to the herbstluftwm autostart close window keybind..

hc keybind $Mod-w chain . close_or_remove . emit_hook focus_window

emit hook

script traps herbstluftwm hook transactions created by window and mouse actions, including those generated by the emit_hook action in keybinds or other scripts..

[[ $(pgrep emit_hook | wc -l) -gt 2 ]] && exit touch ~/.smart_focus herbstclient --idle '(focus_window|focus_changed|rule|focus_frame)' | while read hook name winid do case $name in max) herbstclient set_layout max ;; *) case $hook in focus_window) [[ -e ~/.smart_focus ]] && focus_window & ;; focus_changed) set_border & set_root & ;; focus_frame) [[ -e ~/.smart_focus ]] && focus_frame & ;; esac ;; esac done

Outer case statement anticipates future name extensions.

The emit_hook script is invoked at the end of the herbstluftwm autostart (the code, of which, can simply be merged with autostart instead minus the pgrep statement). This script probably should have been named read_hook but I retained the association with the herbstclient emit_hook command.

toggle focus

of course, we can disable these extended window management behaviours and return to the default manual window tiling of herbstluftwm. That’s why we like manual window tiling..

if [[ -e ~/.smart_focus ]]; then rm -f ~/.smart_focus notify “Smart Focus” Off else touch ~/.smart_focus notify “Smart Focus” On focus_window fi

Add to the herbstluftwm autostart a keybind..

hc keybind $Mod-Super-Control-space spawn toggle_focus

set border

we are not done yet taking advantage of herbstluftwm hooks! set_border highlights the border of the active subframe if it is in max layout and other windows are hidden from view to differentiate it from the border of a simple active window..

tag=$(herbstclient list_monitors | grep '\[FOCUS\]' | cut -d'"' -f2) pkill pulsar_border if [[ $(herbstclient attr tags.$tag.curframe_wcount) -gt 1 ]]; then herbstclient layout | grep ‘[FOCUS]’ | grep -q ‘max:’ && pulsar_border else herbstclient attr theme.active.color ‘#93E0F7’ fi

Normal herbstluftwm focus changes will generate a focus_changed hook but we must add a corresponding emit_hook to our herbstluftwm autostart layout change keybinds because the active window actually does not change focus..

hc keybind $Mod-space chain . spawn toggle_max . emit_hook focus_changed hc keybind $Mod-Shift-space chain . spawn cycle_layout . emit_hook focus_changed hc keybind $Mod-f chain . spawn toggle_fullscreen . emit_hook focus_changed

pulsar border

pulsates the color gradient of the active border..

frequency=0.075 colors="03252F 053847 074B5F 095D75 0A708E 0C83A6 0E97BE 10A8D4 11BCED 29C3EF 41CAF1 57D0F3 70D7F4 88DEF6 93E0F7 A0E4F8 B6EBFA CFF1FB E7F8FD CFF1FB B6EBFA A0E4F8 93E0F7 88DEF6 70D7F4 57D0F3 41CAF1 29C3EF 11BCED 10A8D4 0E97BE 0C83A6 0A708E 095D75 074B5F 053847 03252F 021216" function pulsar() { while true do for i in $colors do herbstclient attr theme.active.color “#$i” & sleep ${frequency}s done done } pulsar &

z3bra’s Monochromatic blog was the inspiration for the pulsating borders (I was originally just going to apply a different flat color.. boring) and it is taken several steps further there with automatic colourscheme generation.

distraction free background

i am pretty boring when it comes to wallpaper backgrounds, having used the same one for years. A predilection for extremely static monochromatic backgrounds makes it easy—there simply aren’t many wallpapers out there that hold me for long.

But even the simplest of images still has a focal point. With window transparency enabled, an even calmer background can be created by blurring the background whenever a window is visible on the desktop..

blur=10 wallpaper='~/images/wallpapers/default' current='/tmp/setroot' [[ -e $current ]] || touch $current root() { (( $(herbstclient attr tags.$(herbstclient attr monitors.$@.tag).client_count) )) && echo “ –on $@ –blur $blur $wallpaper” || echo “ –on $@ $wallpaper” } background="$(root 0)$(root 1)" [[ "$background" = "$(< $current)" ]] && exit eval setroot $background & echo "$background" > $current

Trapping the focus_changed hook allows the pulsating borders and background blur to be set. How cool is that!

Having implemented this, I have to say that alternating wallpaper selections may now become more palatable when blurred in use. This script could easily be enhanced to randomize and show differing images on each monitor. The possibilities are endless!

hook synchronization

is seldom an issue with interactive desktop actions. But automated scripts which perform significant window manipulations can sometimes get ahead of the emit_hook daemon processing with unexpected results affecting window focus and placement.

To prevent this with a few custom dynamic window placement functions, the following function ensures that a specific hook action completes before proceeding..

emit_hook() { process=$(echo $@ | tr ‘_’ ‘ ‘) herbstclient emit_hook $@ if [[ -e ~/.smart_focus ]]; then while ! pgrep -f “$process” do sleep 0.001s done while pgrep -f “$process” do sleep 0.001s done fi }

The code is very specific to the named scripts used in this herbstluftwm implementation. (And since the original draft of this page, a significant rewrite of the herbstluftwm scripts and organization has taken place, which can be seen in the dotfiles).

herbstluftwm pretty much meets my work flow needs and desires. The only thing left is to, perhaps, play around with a traditional status bar, even though I have long eschewed it in favor of my distraction free desktop..

»»  xmodmap shift-dh

comment ?